populateVariantFromSku
- ๐ฌ๐ง English
- ๐ฎ๐น Italian
Function Name: populateVariantFromSku
Author: Domenico Cerone Creation Date: 02/10/2025
Last Reviewer: Domenico Cerone
Trigger: HTTPS (onRequest)
Purpose: Complete workflow for automatic product data population from multiple catalog orders. Handles the entire process: order loading โ product loop โ validation โ download โ mapping โ storage with public URLs. Processes all products from CatalogOrders and creates/updates both Products and Variants collections. Note: EAN/UPC codes are stored at variant level only, not at product level.
Detailed Functionalityโ
This Firebase Function performs a comprehensive 9-step workflow for processing catalog orders with dynamic batch processing optimized for volumes from 5 to 500+ SKUs.
1. CATALOG ORDER LOADINGโ
- Receives
catalogOrderIdas input parameter - Loads document from 'CatalogOrders' collection
- Extracts
list_3d_assets_resultswith product array - Each element contains: skuCode, eanCode, upcCode, isSelected, result
- Processes all products in list_3d_assets_results
2. DYNAMIC PARALLEL BATCH PROCESSING WITH MUTEX SYNCHRONIZATIONโ
Dynamic batch configuration based on SKU volume:
- โค50 SKUs: 10-element batches + 500ms pauses (fast mode)
- 51-200 SKUs: 15-element batches + 1000ms pauses (balanced mode)
-
200 SKUs: 20-element batches + 1500ms pauses (robust mode)
Processing Features:
- Sequential batch processing to avoid Safilo API overload
- Parallel processing within each batch for optimal performance
- NEW: Mutex synchronization to prevent duplicate product creation
โ When 2+ variants of the same modelName are in the same batch
โ Exclusive lock system to serialize Products collection creation
โ Polling with backoff to wait for lock release (100ms โ 2000ms max)
โ Automatic cleanup of expired locks to prevent memory leaks
โ Thread-safe tag creation using
findOrCreateTagThreadSafe()from tagUtils.js โ Prevents duplicate Tags documents in high-concurrency scenarios - Intelligent dynamic pauses between batches for system stability
- Detailed progress logging with memory monitoring for orders >200 SKUs
- Individual product and batch error handling without blocking others
- Separate API call tracking for each product
- Optimized for handling up to 500+ SKUs without timeout (60 minutes maximum)
- Automatic modes: Standard, Optimized, Ultra-Robust
3. CHECKSKU API CALL WITH AUTOMATIC RETRYโ
API Details:
- URL: https://commportal-api.safilo.com/.../spaarkly.checkSKU
- Method: GET
- Parameters: sku, eanCode, upc (at least one required)
- Purpose: Find SKU from EAN/UPC or validate existing SKU
- Response: { sku, eanCode, upc, ... }
For each product with robust retry system:
- ALWAYS calls checkSKU API to get complete data (SKU, EAN, UPC)
- Automatic retry system: 3 attempts per parameter (SKU, EAN, UPC)
- Fallback logic: first all parameters, then one at a time
- Progressive delay between retries: 50ms โ 200ms โ 400ms to avoid overload
- Required to have UPC in mapped JSON
- Robust product validation in Safilo system
- Updates allProductData with all codes for current product
- API call tracking in "apiCalls" object per product with retry status
4. SKU FOLDER CHECK FOR PRODUCTโ
- Checks existence of folder ARS_Library_Product_Data/{skuCode}/
- If NOT EXISTS โ proceeds with API download (STEP 6)
- If EXISTS โ proceeds with existing JSON check (STEP 5)
- (SKU validation already completed in STEP 3)
5. ORIGINAL JSON CHECK FOR PRODUCTโ
- Verifies existence of file: ARS_Library_Product_Data/{skuCode}/json/{skuCode}.json
- If EXISTS: โ Retrieves metadata and token for public URL โ Reads JSON content from Firebase Storage โ Proceeds to mapping and document creation
- If NOT EXISTS โ proceeds to STEP 6 for API download
6. API GETMODELS DOWNLOAD WITH AUTOMATIC RETRY (if JSON doesn't exist)โ
API Details:
- URL: https://commportal-api.safilo.com/.../spaarkly.getModels
- Method: GET
- Parameters: sizeCode={skuCode}
- Purpose: Download complete product data (JSON ~50KB)
- Response: { items: [...], page: 1, itemCount: 1, ... }
Processing Features:
- API call: spaarkly.getModels?sizeCode={skuCode}
- Automatic retry system: 3 attempts with progressive delay (100ms โ 300ms โ 600ms)
- Robust HTTP error handling (404, 500, timeout, network errors)
- JSON response format validation with data verification
- Temporary filesystem save with automatic cleanup
- Firebase Storage upload with UUID token for public URL
- Guaranteed temporary file cleanup even on errors
- Detailed retry and success logging for debugging
- Proceeds to mapping and document creation
7. DOCUMENT CREATION AND MAPPINGโ
Dynamic mapping system:
- Dynamic parsing of mapping_template.xlsx from Firebase Storage
- SAP metadata loading from Firebase Storage (metadata_files/)
- Product image download (8 images: detail 00-07) from Safilo API
- Image API URL: https://safilo-pd-cdn002.safilo.com/damapi/damimage/public/sfcc.getimagenofb
- Method: GET
- Parameters: modelCode, colorCode, lensCode, detail (00-07), imagesize=medium
- Purpose: Download 8 product images (different angles)
- Response: Binary image data (JPEG)
- Data extraction from original JSON based on template rules
- Automatic SAP codes translation
- Special field handling: โ SPECIAL_PRODUCT_DESCRIPTIONS: Creates separate language fields (description_en, description_it, etc.) โ SPECIAL_IMAGE_NAMES: Extracts public URLs with tokens โ specific posters (00,07,02,01) + list_images array
- Mapped JSON save on Storage with public URL
- Create/update document in Products collection (without catalogOrdersRef, no EAN/UPC codes stored here)
- Create/update document in Variants collection (batch, catalogOrdersRef, and prioritiesModeling extracted from CatalogOrder, EAN/UPC codes stored here)
Related Components:
- createProductDocument - Handles Products collection management with thread-safe tag creation
- createVariantDocument - Handles Variants collection management with brand normalization
- tagUtils - Provides thread-safe tag creation utilities with mutex synchronization to prevent duplicates
Brand Normalization Systemโ
The function includes an intelligent brand normalization system that applies business rules to standardize brand names from SAP data to consistent marketing brand names.
Brand Mapping Rules:
- Hugo brands: "HUGO" โ "HUGO EYEWEAR"
- Boss brands: "HUGO BOSS", "BOSS ORANGE" โ "BOSS EYEWEAR"
- Carrera brands: "CARRERA BY JIMMYCHOO", "CARRERA BIKE", "CARRERA SNOW", "CARRERA DUCATI" โ "CARRERA"
- Polaroid brands: "POLAROID ANCILLARIES", "POLAROID KIDS", "POLAROID STAYSAFE" โ "POLAROID"
- Smith brands: "SMITH FASHION & ACC.", "SMITH BIKE HELMETS", "SMITH SNOW", "SMITH BIKE GOGGLES", "PRIVATE LABEL SMITH", "SUNCLOUD" โ "SMITH OPTICS"
- Other brands: Remain unchanged
Implementation: The mapToNormalizedBrand() function is called automatically during data mapping to ensure consistent brand naming across both Products and Variants collections.
Benefits:
- Consistent brand representation across all collections
- Simplified brand management and filtering
- Alignment with marketing brand guidelines
- Automatic application without manual intervention
Mutex Synchronization Systemโ
Problem Solved: When multiple variants of the same product (same modelName) are processed in parallel within the same batch, they could attempt to create the same Products document simultaneously, leading to race conditions and potential duplicates.
Solution: Exclusive lock system using Map-based mutex:
- Lock Acquisition: Before creating/updating a Products document, the function acquires an exclusive lock using the modelName as key
- Lock Key Format:
PRODUCT_CREATE_\{modelName\} - Polling Mechanism: If a lock is already held, the function waits with exponential backoff (100ms โ 2000ms max)
- Automatic Cleanup: Expired locks (older than 10 minutes) are automatically cleaned up to prevent memory leaks
- Granular Locking: Each modelName has its own lock, so different products can be processed simultaneously
- Error Safety: Locks are released in finally blocks to ensure cleanup even on errors
Benefits:
- Prevents duplicate Products documents
- Maintains data consistency in high-concurrency scenarios
- Optimizes performance by allowing parallel processing of different products
- Provides automatic recovery from stuck locks
Variants Collection Fields Populationโ
The function populates the following fields in the Variants collection with data extracted from the CatalogOrder and product processing:
Base Fields:
skuModelโ skuModel (primary identifier)eanCodeโ eanCodeframeColorโ frameColorlensesColorโ lensesColorglassesNameโ glassesNamemainBrandRefโ ID brand (searches/creates in MainBrands collection)upcCodeโ upcCodebatchโ batch (extracted from CatalogOrder)productRefโ ID of parent Products documentcatalogOrdersRefโ ID of CatalogOrder that generated the variantprioritiesModelingโ priority (extracted from product in list_3d_assets_results)
Image Fields:
posterโ poster (view 00 - main frontal)poster2โ poster2 (view 07 - side angle)poster3โ poster3 (view 02 - frontal detail)poster4โ poster4 (view 01 - alternative angle)
Size Object (all fields as strings):
size.bridgeโ bridgesize.frameWidthโ frameWidthsize.lensHeightโ lensHeightsize.lensWidthโ lensWidthsize.sizeโ sizesize.templeLengthโ templeLengthsize.frontHeightโ frontHeightsize.hingeToHingeโ hingeToHingesize.lensCircumferenceโ lensCircumferencesize.lensAngleโ lensAnglesize.phantoscopicAngleโ phantoscopicAngle
Timestamp Fields (as JavaScript Date objects):
lastUpdateโ current timestamp (always updated, Date object)skuReleaseDateโ skuReleaseDate (if present in mapped JSON, Date object)skuEndDateโ skuEndDate (if present in mapped JSON, Date object)advStartDateโ advStartDate (if present in mapped JSON, Date object)advEndDateโ advEndDate (if present in mapped JSON, Date object)
Tags Arrays:
list_size_color_tagsโ [frameColor tag ID, size tag ID] (searches/creates in Tags collection)list_imagesโ list_images (array of objects with view and url of images)
Brand Normalization:
The mainBrandRef field is automatically normalized according to business rules:
- Hugo brands: "HUGO" โ "HUGO EYEWEAR"
- Boss brands: "HUGO BOSS", "BOSS ORANGE" โ "BOSS EYEWEAR"
- Carrera brands: "CARRERA BY JIMMYCHOO", "CARRERA BIKE", "CARRERA SNOW", "CARRERA DUCATI" โ "CARRERA"
- Polaroid brands: "POLAROID ANCILLARIES", "POLAROID KIDS", "POLAROID STAYSAFE" โ "POLAROID"
- Smith brands: "SMITH FASHION & ACC.", "SMITH BIKE HELMETS", "SMITH SNOW", "SMITH BIKE GOGGLES", "PRIVATE LABEL SMITH", "SUNCLOUD" โ "SMITH OPTICS"
- Other brands remain unchanged
Products Collection Fields Populationโ
The function populates the following fields in the Products collection with data extracted from the product processing:
Base Fields:
modelNameโ glassesName (primary identifier)ageโ catAgeForGendereanCodeโ eanCodemanufacturedProductStatusโ manufacturedProductStatusrxAbleโ rxAblemainBrandRefโ ID brand (searches/creates in MainBrands collection)upcCodeโ upcCode
Image Fields (from current variant):
imgUrlโ posterthumbnailโ posterurlImageโ poster
Timestamp Fields:
lastUpdateโ current timestamp (always updated, Date object)productReleaseDateโ productReleaseDate (if present in mapped JSON, Date object)productEndDateโ productEndDate (if present in mapped JSON, Date object)
Multilingual Descriptions:
descriptionEnโ description_endescriptionItโ description_itdescriptionEsโ description_esdescriptionFrโ description_frdescriptionDeโ description_de
Tags Arrays (aggregated from all variants):
list_frame_color_tagsโ [frameColor from all variants of the product]list_size_tagsโ [size from all variants of the product]list_line_tagsโ [nomeLinea]list_tagsโ [catType, catAgeForGender, catGender, catForma, catMaterialOne, polarised, catLensesTreat, hingeType]
Variants Management:
variants_mapโ array with entry for each product variant:- eanCode, id, publishedInARSLibrary (""), skuCode, upcCode, variantName (glassesName)
list_variantsโ [ID of all product variants]availableVariantsโ always 0 (logic managed externally)
Input Data Structureโ
The function expects the CatalogOrder document to contain the following structure:
Required Fields:
clientId: ID of the clientlist_3d_assets_results: array of products with skuCode, eanCode, upcCode, isSelected, result, priorityorderName: name of the orderprofile: client emailquoteResponse: response status (e.g., "accepted")batch: batch identifier for variants
Product Structure in list_3d_assets_results:
{
"skuCode": "20637008650QT",
"eanCode": "0762753916013",
"upcCode": "762753916013",
"isSelected": true,
"result": "Available",
"priority": "High"
}
Priority Values:
The priority field from the product is used to populate the prioritiesModeling field in the Variants collection. Common values include:
- "High" - High priority for modeling
- "Medium" - Medium priority for modeling
- "Low" - Low priority for modeling
- "" (empty) - No specific priority
8. CATALOG ORDER UPDATEโ
- Updates list_3d_assets_results with productRef and variantRef for each processed product
- Maintains all other catalog order fields unchanged
- Sets status = "working_3d_assets" at operation end
9. PROFILES UPDATEโ
- Adds catalogOrderId to list_3d_catalogOrders arrays of appropriate profiles
- Requester profile: extracts 'profile' field from CatalogOrder
- Admin profiles: searches all profiles with role = 'Admin'
- ModellerSupervisor profiles: searches all profiles with role = 'ModellerSupervisor'
- Duplicate verification: doesn't add if catalogOrderId already present
- Robust error handling: continues even if some profiles fail
- Final response with all processed product results and profile updates
Input (Payload)โ
Method: POST/GET
Headers:
Content-Type: application/json(for POST requests)
Body (POST) or Query Parameters (GET):
{
"catalogOrderId": "VHNGMFgVezqLDrXBv4iV"
}
Parameters:
catalogOrderId(string, required): Unique identifier of the catalog order to process
Output (Success)โ
{
"success": true,
"catalogOrderId": "VHNGMFgVezqLDrXBv4iV",
"totalProducts": 3,
"successCount": 2,
"errorCount": 1,
"processedProducts": [
{
"success": true,
"skuCode": "20637008650QT",
"eanCode": "0762753916013",
"upcCode": "762753916013",
"productRef": "auto_generated_product_id",
"variantRef": "auto_generated_variant_id",
"productOperation": "create",
"variantOperation": "create",
"message": "Product 20637008650QT processed successfully",
"apiCalls": {
"checkSKU (EAN, UPC, SKU)": "https://...spaarkly.checkSKU?sku=...",
"getModels (file .json)": "https://...spaarkly.getModels?sizeCode=...",
"getImages (thumbnail images)": "https://safilo-pd-cdn002.safilo.com/... (or '(cached)' if existing)"
}
}
],
"profileUpdateResult": {
"success": true,
"totalUpdated": 5,
"totalErrors": 0,
"details": {
"requesterProfile": \{ "updated": true, "error": null \},
"adminProfiles": \{ "count": 3, "updated": 3, "errors": [] \},
"supervisorProfiles": \{ "count": 2, "updated": 2, "errors": [] \}
}
},
"message": "Processing completed for CatalogOrder VHNGMFgVezqLDrXBv4iV: 2/3 products processed successfully",
"recap": "CatalogOrder VHNGMFgVezqLDrXBv4iV loading โ 3 selected products โ 2 products processed successfully โ 1 products with errors โ CatalogOrder update completed โ status set to working_3d_assets โ profile updates: 5 profiles updated",
"allApiCalls": {
"Product_1_20637008650QT": \{ ... \},
"Product_2_1095638075515": \{ ... \},
"Product_3_INVALID_SKU": \{ ... \}
}
}
Technical Specificationsโ
Firebase Function Configuration:
- Timeout: 3600 seconds (60 minutes) - maximum for HTTP Functions v2
- Memory: 2GiB - optimized for extreme volumes (300-500 SKUs)
- Region: europe-central2 - optimal performance for Europe
- CORS: Enabled for frontend calls
Performance Guarantees by Volume:
- 5-50 SKUs: 15 seconds - 2 minutes (standard mode)
- 51-200 SKUs: 3-12 minutes (optimized mode)
- 201-500 SKUs: 15-35 minutes (ultra-robust mode)
- No timeout guaranteed up to 500 SKUs
Testingโ
URL (if HTTPS): http://127.0.0.1:5001/arshadesstaging/europe-central2/populateVariantFromSku
Test with Emulator:
- Start Firebase emulator:
firebase emulators:start --only functions - Ensure you're using Node.js version 20:
nvm use 20 - Test with curl:
curl -X POST "http://127.0.0.1:5001/arshadesstaging/europe-central2/populateVariantFromSku" \
-H "Content-Type: application/json" \
-d '{
"catalogOrderId": "VHNGMFgVezqLDrXBv4iV"
}'
Postman Testing:
- Method: POST
- URL:
http://127.0.0.1:5001/arshadesstaging/europe-central2/populateVariantFromSku - Headers:
- Key:
Content-Type - Value:
application/json
- Key:
- Body: raw JSON (see examples above)
Deploy Commandโ
firebase deploy --only functions:populateVariantFromSku
Production URLโ
Live Function: https://europe-central2-arshades-7e18a.cloudfunctions.net/populateVariantFromSku
Function Name: populateVariantFromSku
Autore: Domenico Cerone Data di creazione: 02/10/2025
Last Reviewer: Domenico Cerone
Trigger: HTTPS (onRequest)
Purpose: Workflow completo per il popolamento automatico dei dati prodotto da ordini catalogo multipli. Gestisce l'intero processo: caricamento ordine โ loop prodotti โ validazione โ download โ mapping โ storage con URL pubblici. Processa tutti i prodotti da CatalogOrders e crea/aggiorna sia le collezioni Products che Variants. Nota: I codici EAN/UPC sono memorizzati solo a livello di variante, non a livello di prodotto.
Funzionamento Dettagliatoโ
Questa Firebase Function esegue un workflow completo di 9 step per il processing di ordini catalogo con batch processing dinamico ottimizzato per volumi da 5 a 500+ SKU.
1. CARICAMENTO CATALOG ORDERโ
- Riceve
catalogOrderIdcome parametro di input - Carica documento dalla collezione 'CatalogOrders'
- Estrae
list_3d_assets_resultscon array di prodotti - Ogni elemento contiene: skuCode, eanCode, upcCode, isSelected, result
- Processa tutti i prodotti in list_3d_assets_results
2. PROCESSING BATCH PARALLELO DINAMICOโ
Configurazione batch dinamica basata sul volume di SKU:
- โค50 SKU: batch da 10 elementi + pause 500ms (modalitร veloce)
- 51-200 SKU: batch da 15 elementi + pause 1000ms (modalitร bilanciata)
-
200 SKU: batch da 20 elementi + pause 1500ms (modalitร robusta)
Caratteristiche Processing:
- Processing batch sequenziale per evitare sovraccarico API Safilo
- Processing parallelo all'interno di ogni batch per prestazioni ottimali
- NUOVO: Mutex sincronizzazione per evitare creazione prodotti duplicati
โ Quando 2+ varianti dello stesso modelName sono nello stesso batch
โ Sistema di lock esclusivo per serializzare la creazione di Products
โ Polling con backoff per attendere rilascio lock (100ms โ 2000ms max)
โ Cleanup automatico lock scaduti per evitare memory leak
โ Creazione tag thread-safe usando
findOrCreateTagThreadSafe()da tagUtils.js โ Previene documenti Tags duplicati in scenari di alta concorrenza - Pause intelligenti dinamiche tra batch per stabilitร del sistema
- Logging dettagliato del progresso con monitoraggio memoria per ordini >200 SKU
- Gestione errori per singolo prodotto e per batch senza bloccare gli altri
- Tracking chiamate API per ogni prodotto separatamente
- Ottimizzato per gestire fino a 500+ SKU senza timeout (60 minuti massimo)
- Modalitร automatiche: Standard, Ottimizzata, Ultra-Robusta
3. CHIAMATA CHECKSKU API CON RETRY AUTOMATICOโ
Dettagli API:
- URL: https://commportal-api.safilo.com/.../spaarkly.checkSKU
- Metodo: GET
- Parametri: sku, eanCode, upc (almeno uno richiesto)
- Scopo: Trovare SKU da EAN/UPC o validare SKU esistente
- Response: { sku, eanCode, upc, ... }
Per ogni prodotto con sistema retry robusto:
- SEMPRE chiama checkSKU API per ottenere dati completi (SKU, EAN, UPC)
- Sistema di retry automatico: 3 tentativi per ogni parametro (SKU, EAN, UPC)
- Logica di fallback: prima tutti i parametri, poi uno alla volta
- Delay progressivo tra retry: 50ms โ 200ms โ 400ms per evitare sovraccarico
- Necessario per avere UPC nel JSON mappato
- Validazione prodotto robusta nel sistema Safilo
- Aggiorna allProductData con tutti i codici per prodotto corrente
- Tracking chiamata API in oggetto "apiCalls" per prodotto con stato retry
4. CONTROLLO CARTELLA SKU PER PRODOTTOโ
- Controlla esistenza cartella ARS_Library_Product_Data/{skuCode}/
- Se NON ESISTE โ procede con download da API (STEP 6)
- Se ESISTE โ procede con controllo JSON esistente (STEP 5)
- (Validazione SKU giร completata nello STEP 3)
5. CONTROLLO JSON ORIGINALE PER PRODOTTOโ
- Verifica esistenza file: ARS_Library_Product_Data/{skuCode}/json/{skuCode}.json
- Se ESISTE: โ Recupera metadata e token per URL pubblico โ Legge contenuto JSON da Firebase Storage โ Procede al mapping e creazione documenti
- Se NON ESISTE โ procede allo STEP 6 per download da API
6. DOWNLOAD DA API GETMODELS CON RETRY AUTOMATICO (se JSON non esiste)โ
Dettagli API:
- URL: https://commportal-api.safilo.com/.../spaarkly.getModels
- Metodo: GET
- Parametri: sizeCode={skuCode}
- Scopo: Scaricare dati completi prodotto (JSON ~50KB)
- Response: { items: [...], page: 1, itemCount: 1, ... }
Caratteristiche Processing:
- Chiamata API: spaarkly.getModels?sizeCode={skuCode}
- Sistema di retry automatico: 3 tentativi con delay progressivo (100ms โ 300ms โ 600ms)
- Gestione errori HTTP robusta (404, 500, timeout, network errors)
- Validazione formato JSON response con controllo dati
- Salvataggio temporaneo su filesystem locale con cleanup automatico
- Upload su Firebase Storage con token UUID per URL pubblico
- Cleanup file temporanei garantito anche in caso di errori
- Logging dettagliato retry e successi per debugging
- Procede al mapping e creazione documenti
7. CREAZIONE DOCUMENTI E MAPPINGโ
Sistema mapping dinamico:
- Parsing dinamico mapping_template.xlsx da Firebase Storage
- Caricamento metadata SAP da Firebase Storage (metadata_files/)
- Download immagini prodotto (8 immagini: detail 00-07) da Safilo API
- URL API Immagini: https://safilo-pd-cdn002.safilo.com/damapi/damimage/public/sfcc.getimagenofb
- Metodo: GET
- Parametri: modelCode, colorCode, lensCode, detail (00-07), imagesize=medium
- Scopo: Scaricare 8 immagini prodotto (diverse angolazioni)
- Response: Binary image data (JPEG)
- Estrazione dati dal JSON originale basata su template rules
- Applicazione traduzioni SAP codes automatiche
- Gestione campi speciali: โ SPECIAL_PRODUCT_DESCRIPTIONS: Crea campi separati per lingua (description_en, description_it, etc.) โ SPECIAL_IMAGE_NAMES: Estrae URL pubblici con token โ poster specifici (00,07,02,01) + array list_images
- Salvataggio JSON mappato su Storage con URL pubblico
- Creazione/aggiornamento documento nella collezione Products (senza catalogOrdersRef, nessun codice EAN/UPC memorizzato qui)
- Creazione/aggiornamento documento nella collezione Variants (batch e catalogOrdersRef estratti da CatalogOrder, codici EAN/UPC memorizzati qui)
Componenti Correlati:
- createProductDocument - Gestisce la collezione Products con creazione tag thread-safe
- createVariantDocument - Gestisce la collezione Variants con normalizzazione brand
- tagUtils - Fornisce utilitร per creazione tag thread-safe con sincronizzazione mutex per prevenire duplicati
Sistema Normalizzazione Brandโ
La funzione include un sistema intelligente di normalizzazione brand che applica regole di business per standardizzare i nomi brand dai dati SAP ai nomi brand marketing consistenti.
Regole Mappatura Brand:
- Brand Hugo: "HUGO" โ "HUGO EYEWEAR"
- Brand Boss: "HUGO BOSS", "BOSS ORANGE" โ "BOSS EYEWEAR"
- Brand Carrera: "CARRERA BY JIMMYCHOO", "CARRERA BIKE", "CARRERA SNOW", "CARRERA DUCATI" โ "CARRERA"
- Brand Polaroid: "POLAROID ANCILLARIES", "POLAROID KIDS", "POLAROID STAYSAFE" โ "POLAROID"
- Brand Smith: "SMITH FASHION & ACC.", "SMITH BIKE HELMETS", "SMITH SNOW", "SMITH BIKE GOGGLES", "PRIVATE LABEL SMITH", "SUNCLOUD" โ "SMITH OPTICS"
- Altri brand: Rimangono invariati
Implementazione: La funzione mapToNormalizedBrand() viene chiamata automaticamente durante il mapping dati per garantire nomenclatura brand consistente in entrambe le collezioni Products e Variants.
Vantaggi:
- Rappresentazione brand consistente in tutte le collezioni
- Gestione e filtraggio brand semplificato
- Allineamento con le linee guida brand marketing
- Applicazione automatica senza intervento manuale
Sistema Mutex Sincronizzazioneโ
Problema Risolto: Quando piรน varianti dello stesso prodotto (stesso modelName) vengono processate in parallelo nello stesso batch, potrebbero tentare di creare lo stesso documento Products simultaneamente, causando race condition e potenziali duplicati.
Soluzione: Sistema di lock esclusivo usando mutex basato su Map:
- Acquisizione Lock: Prima di creare/aggiornare un documento Products, la funzione acquisisce un lock esclusivo usando il modelName come chiave
- Formato Chiave Lock:
PRODUCT_CREATE_\{modelName\} - Meccanismo Polling: Se un lock รจ giร detenuto, la funzione attende con backoff esponenziale (100ms โ 2000ms max)
- Cleanup Automatico: Lock scaduti (piรน vecchi di 10 minuti) vengono automaticamente puliti per evitare memory leak
- Locking Granulare: Ogni modelName ha il suo lock, cosรฌ prodotti diversi possono essere processati simultaneamente
- Sicurezza Errori: I lock vengono rilasciati nei blocchi finally per garantire cleanup anche in caso di errori
Vantaggi:
- Previene documenti Products duplicati
- Mantiene consistenza dati in scenari alta concorrenza
- Ottimizza performance permettendo processing parallelo di prodotti diversi
- Fornisce recovery automatico da lock bloccati
Campi Popolati Collezione Variantsโ
La funzione popola i seguenti campi nella collezione Variants con dati estratti dal CatalogOrder e dall'elaborazione del prodotto:
Campi Base:
skuModelโ skuModel (identificatore principale)eanCodeโ eanCodeframeColorโ frameColorlensesColorโ lensesColorglassesNameโ glassesNamemainBrandRefโ ID brand (cerca/crea nella collezione MainBrands)upcCodeโ upcCodebatchโ batch (estratto dal CatalogOrder)productRefโ ID del documento Products padrecatalogOrdersRefโ ID del CatalogOrder che ha generato la varianteprioritiesModelingโ priority (estratto dal prodotto in list_3d_assets_results)
Campi Immagini:
posterโ poster (vista 00 - frontale principale)poster2โ poster2 (vista 07 - angolazione laterale)poster3โ poster3 (vista 02 - dettaglio frontale)poster4โ poster4 (vista 01 - angolazione alternativa)
Oggetto Size (tutti i campi come stringhe):
size.bridgeโ bridgesize.frameWidthโ frameWidthsize.lensHeightโ lensHeightsize.lensWidthโ lensWidthsize.sizeโ sizesize.templeLengthโ templeLengthsize.frontHeightโ frontHeightsize.hingeToHingeโ hingeToHingesize.lensCircumferenceโ lensCircumferencesize.lensAngleโ lensAnglesize.phantoscopicAngleโ phantoscopicAngle
Campi Timestamp (come oggetti Date JavaScript):
lastUpdateโ timestamp corrente (sempre aggiornato, oggetto Date)skuReleaseDateโ skuReleaseDate (se presente nel JSON mappato, oggetto Date)skuEndDateโ skuEndDate (se presente nel JSON mappato, oggetto Date)advStartDateโ advStartDate (se presente nel JSON mappato, oggetto Date)advEndDateโ advEndDate (se presente nel JSON mappato, oggetto Date)
Array Tags:
list_size_color_tagsโ [ID tag frameColor, ID tag size] (cerca/crea nella collezione Tags)list_imagesโ list_images (array di oggetti con view e url delle immagini)
Normalizzazione Brand:
Il campo mainBrandRef viene automaticamente normalizzato secondo le regole di business:
- Brand Hugo: "HUGO" โ "HUGO EYEWEAR"
- Brand Boss: "HUGO BOSS", "BOSS ORANGE" โ "BOSS EYEWEAR"
- Brand Carrera: "CARRERA BY JIMMYCHOO", "CARRERA BIKE", "CARRERA SNOW", "CARRERA DUCATI" โ "CARRERA"
- Brand Polaroid: "POLAROID ANCILLARIES", "POLAROID KIDS", "POLAROID STAYSAFE" โ "POLAROID"
- Brand Smith: "SMITH FASHION & ACC.", "SMITH BIKE HELMETS", "SMITH SNOW", "SMITH BIKE GOGGLES", "PRIVATE LABEL SMITH", "SUNCLOUD" โ "SMITH OPTICS"
- Altri brand rimangono invariati
Campi Popolati Collezione Productsโ
La funzione popola i seguenti campi nella collezione Products con dati estratti dall'elaborazione del prodotto:
Campi Base:
modelNameโ glassesName (identificatore principale)ageโ catAgeForGendereanCodeโ eanCodemanufacturedProductStatusโ manufacturedProductStatusrxAbleโ rxAblemainBrandRefโ ID brand (cerca/crea nella collezione MainBrands)upcCodeโ upcCode
Campi Immagini (dalla variante corrente):
imgUrlโ posterthumbnailโ posterurlImageโ poster
Campi Timestamp:
lastUpdateโ timestamp corrente (sempre aggiornato, oggetto Date)productReleaseDateโ productReleaseDate (se presente nel JSON mappato, oggetto Date)productEndDateโ productEndDate (se presente nel JSON mappato, oggetto Date)
Descrizioni Multilingua:
descriptionEnโ description_endescriptionItโ description_itdescriptionEsโ description_esdescriptionFrโ description_frdescriptionDeโ description_de
Array Tags (aggregati da tutte le varianti):
list_frame_color_tagsโ [frameColor da tutte le varianti del prodotto]list_size_tagsโ [size da tutte le varianti del prodotto]list_line_tagsโ [nomeLinea]list_tagsโ [catType, catAgeForGender, catGender, catForma, catMaterialOne, polarised, catLensesTreat, hingeType]
Gestione Varianti:
variants_mapโ array con entry per ogni variante del prodotto:- eanCode, id, publishedInARSLibrary (""), skuCode, upcCode, variantName (glassesName)
list_variantsโ [ID di tutte le varianti del prodotto]availableVariantsโ sempre 0 (logica gestita esternamente)
Struttura Dati Inputโ
La funzione si aspetta che il documento CatalogOrder contenga la seguente struttura:
Campi Richiesti:
clientId: ID del clientelist_3d_assets_results: array di prodotti con skuCode, eanCode, upcCode, isSelected, result, priorityorderName: nome dell'ordineprofile: email del clientequoteResponse: stato della risposta (es. "accepted")batch: identificatore batch per le varianti
Struttura Prodotto in list_3d_assets_results:
{
"skuCode": "20637008650QT",
"eanCode": "0762753916013",
"upcCode": "762753916013",
"isSelected": true,
"result": "Available",
"priority": "High"
}
Valori Priority:
Il campo priority del prodotto viene utilizzato per popolare il campo prioritiesModeling nella collezione Variants. I valori comuni includono:
- "High" - Prioritร alta per la modellazione
- "Medium" - Prioritร media per la modellazione
- "Low" - Prioritร bassa per la modellazione
- "" (vuoto) - Nessuna prioritร specifica
8. AGGIORNAMENTO CATALOG ORDERโ
- Aggiorna list_3d_assets_results con productRef e variantRef per ogni prodotto processato
- Mantiene tutti gli altri campi dell'ordine catalogo invariati
- Imposta status = "working_3d_assets" a fine operazione
9. AGGIORNAMENTO PROFILIโ
- Aggiunge catalogOrderId agli array list_3d_catalogOrders dei profili appropriati
- Profilo richiedente: estrae campo 'profile' dal CatalogOrder
- Profili Admin: cerca tutti i profili con role = 'Admin'
- Profili ModellerSupervisor: cerca tutti i profili con role = 'ModellerSupervisor'
- Verifica duplicati: non aggiunge se catalogOrderId giร presente
- Gestione errori robusta: continua anche se alcuni profili falliscono
- Response finale con risultati di tutti i prodotti processati e aggiornamenti profili
Input (Payload)โ
Metodo: POST/GET
Headers:
Content-Type: application/json(per richieste POST)
Body (POST) o Parametri Query (GET):
{
"catalogOrderId": "VHNGMFgVezqLDrXBv4iV"
}
Parametri:
catalogOrderId(string, richiesto): Identificatore unico dell'ordine catalogo da processare
Output (Successo)โ
{
"success": true,
"catalogOrderId": "VHNGMFgVezqLDrXBv4iV",
"totalProducts": 3,
"successCount": 2,
"errorCount": 1,
"processedProducts": [
{
"success": true,
"skuCode": "20637008650QT",
"eanCode": "0762753916013",
"upcCode": "762753916013",
"productRef": "auto_generated_product_id",
"variantRef": "auto_generated_variant_id",
"productOperation": "create",
"variantOperation": "create",
"message": "Prodotto 20637008650QT processato con successo",
"apiCalls": {
"checkSKU (EAN, UPC, SKU)": "https://...spaarkly.checkSKU?sku=...",
"getModels (file .json)": "https://...spaarkly.getModels?sizeCode=...",
"getImages (thumbnail images)": "https://safilo-pd-cdn002.safilo.com/... (o '(cached)' se esistenti)"
}
}
],
"profileUpdateResult": {
"success": true,
"totalUpdated": 5,
"totalErrors": 0,
"details": {
"requesterProfile": \{ "updated": true, "error": null \},
"adminProfiles": \{ "count": 3, "updated": 3, "errors": [] \},
"supervisorProfiles": \{ "count": 2, "updated": 2, "errors": [] \}
}
},
"message": "Processing completato per CatalogOrder VHNGMFgVezqLDrXBv4iV: 2/3 prodotti processati con successo",
"recap": "caricamento CatalogOrder VHNGMFgVezqLDrXBv4iV โ 3 prodotti selezionati โ 2 prodotti processati con successo โ 1 prodotti con errori โ aggiornamento CatalogOrder completato โ status impostato su working_3d_assets โ aggiornamento profili: 5 profili aggiornati",
"allApiCalls": {
"Product_1_20637008650QT": \{ ... \},
"Product_2_1095638075515": \{ ... \},
"Product_3_INVALID_SKU": \{ ... \}
}
}
Specifiche Tecnicheโ
Configurazione Firebase Function:
- Timeout: 3600 secondi (60 minuti) - massimo per HTTP Functions v2
- Memoria: 2GiB - ottimizzata per volumi estremi (300-500 SKU)
- Regione: europe-central2 - performance ottimali per Europa
- CORS: Abilitato per chiamate da frontend
Prestazioni Garantite per Volume:
- 5-50 SKU: 15 secondi - 2 minuti (modalitร standard)
- 51-200 SKU: 3-12 minuti (modalitร ottimizzata)
- 201-500 SKU: 15-35 minuti (modalitร ultra-robusta)
- Nessun timeout garantito fino a 500 SKU
Testingโ
URL (if HTTPS): http://127.0.0.1:5001/arshadesstaging/europe-central2/populateVariantFromSku
Test con Emulator:
- Avviare l'emulatore Firebase:
firebase emulators:start --only functions - Assicurarsi di usare Node.js versione 20:
nvm use 20 - Testare con curl:
curl -X POST "http://127.0.0.1:5001/arshadesstaging/europe-central2/populateVariantFromSku" \
-H "Content-Type: application/json" \
-d '{
"catalogOrderId": "VHNGMFgVezqLDrXBv4iV"
}'
Test con Postman:
- Metodo: POST
- URL:
http://127.0.0.1:5001/arshadesstaging/europe-central2/populateVariantFromSku - Headers:
- Key:
Content-Type - Value:
application/json
- Key:
- Body: raw JSON (vedi esempi sopra)
Deploy Commandโ
firebase deploy --only functions:populateVariantFromSku
URL di Produzioneโ
Funzione Live: https://europe-central2-arshades-7e18a.cloudfunctions.net/populateVariantFromSku